﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Xml;

namespace LibrarySync2.Business.Xml
{
    // copy-paste this attribute in front of your collection.
    // 'yourBaseClass' is the base class of your collection
    //[XmlElement(Type=typeof(CollectionSerializer<yourBaseClass>))]

    /// <summary>
    ///
    ///Either add an attribute directly onto the base class property if you have access to the source code:
    ///
    ///      [XmlElement(Type=typeof(CollectionSerializer&lt;yourBaseClass&gt;))]
    ///     
    ///
    ///Or pass a 'virtual attribute' to the constructor of XmlSerializer if you don't have the source code:
    ///
    ///XmlAttributeOverrides attributeOverrides = new XmlAttributeOverrides();
    ///attributes.XmlElements.Add(new XmlElementAttribute(typeof(&lt;newClassName&gt;Serializer)));
    ///attributeOverrides.Add(typeof(&lt;typeWithAPropertyHoldingABaseType&gt;), "&lt;nameOfPropertyHoldingABaseType&gt;", attributes);
    ///
    ///serializer = new XmlSerializer(typeof(&lt;anyTypeThatIndirectlyReferences
    ///                                    TypeWithAPropertyHoldingABaseType&gt;), attributeOverrides);
    /// </summary>
    /// <remarks>Reproduced from: http://www.codeproject.com/KB/XML/xmlserializerforunknown.aspx</remarks>
    /// <typeparam name="BaseType">The base type for the collection you want to serialize.</typeparam>
    public class CollectionSerializer<BaseType> : IXmlSerializable //where BaseType: SomeObject
    {
        #region Static

        /// <summary>
        /// casting implicitly lets the serializer recognize the type automaticall
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        public static implicit operator CollectionSerializer<BaseType>(BaseType p)
        {
            return p == null ? null : new CollectionSerializer<BaseType>(p);
        }
        /// <summary>
        /// casting implicitly lets the serializer recognize the type automaticall
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        public static implicit operator BaseType(CollectionSerializer<BaseType> p)
        {
            return p == null ? default(BaseType) : p.Parameters;
        }

        #endregion Static


        #region Constructors
        /// <summary>
        /// When using this construcor Parameters must be set
        /// </summary>
        public CollectionSerializer() { }

        public CollectionSerializer(BaseType parameters)
        {
            this.parameters = parameters;
        }
        #endregion Constructors


        #region Properties

        private BaseType parameters;

        /// <summary>
        /// this is the underlying object that will be serialized
        /// </summary>
        public BaseType Parameters
        {
            get { return parameters; }
        }


        #endregion Properties

        #region IXmlSerializable Implementation

        /// <summary>
        /// no schema needed - returning null
        /// </summary>
        /// <returns></returns>
        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(XmlReader reader)
        {
            Type type = Type.GetType(reader.GetAttribute("type"));
            reader.ReadStartElement();
            this.parameters = (BaseType)new  XmlSerializer(type).Deserialize(reader);
            reader.ReadEndElement();
        }

        public void WriteXml(XmlWriter writer)
        {
            writer.WriteAttributeString("type", parameters.GetType().ToString());
            new XmlSerializer(parameters.GetType()).Serialize(writer, parameters);
        }
        #endregion IXmlSerializable Implementation

    }
}
